package org.anyin.gitee.cloud.lib.core.extension;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class DefaultExtensionHandlerFactoryImpl implements IExtensionHandlerFactory, ApplicationContextAware {

    private final Map<Enum, List<IExtensionHandler>> serviceListCache = new ConcurrentHashMap();
    private final Map<ExtensionCacheKey, IExtensionHandler> serviceCache = new ConcurrentHashMap();

    @Override
    public <Y extends Enum<Y>> void addExtensionHandler(IExtensionHandler<Y> extensionHandler) {
        Assert.notNull(extensionHandler.extension(), "add extension handler failed, bean class " + extensionHandler.getClass().getName() + " extension is null");
        serviceListCache.putIfAbsent(extensionHandler.extension(), new LinkedList<>());
        serviceListCache.get(extensionHandler.extension()).add(extensionHandler);
    }

    @Override
    public <T extends IExtensionHandler<Y>, Y extends Enum<Y>> T getExtensionHandler(Y extension, Class<T> type) {
        ExtensionCacheKey<Y> cacheKey = new ExtensionCacheKey(extension, type);
        IExtensionHandler result = this.serviceCache.get(cacheKey);
        if (result == null) {
            List<IExtensionHandler> payPlatformAbles = serviceListCache.getOrDefault(extension, Collections.synchronizedList(Collections.emptyList()));
            for (IExtensionHandler payPlatformAble : payPlatformAbles) {
                if (type.isAssignableFrom(payPlatformAble.getClass())) {
                    result = payPlatformAble;
                    serviceCache.put(cacheKey, result);
                    break;
                }
            }
            if (result == null) {
                log.warn("No IExtensionHandler found by CacheKey : " + cacheKey + " !");
            }
        }
        return (T) result;

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String,IExtensionHandler> handlerMap = applicationContext.getBeansOfType(IExtensionHandler.class);
        log.info("start loading extension handler ");
        long start = System.currentTimeMillis();
        handlerMap.forEach((k, v) -> {
            //排除组合类自己
            if (!this.getClass().isAssignableFrom(v.getClass())) {
                addExtensionHandler(v);
            }
        });
        long end = System.currentTimeMillis();
        log.info("done loaded extension handler ，time : {}, count : {}", end - start, handlerMap.size());

    }
}
